﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Diagnostics;

namespace Gmis.VideoConvert
{
    public class VideoEncoder : IDisposable
    {
      	
		#region Events
		/// <summary>
		/// Occurs when Progress changes.
		/// </summary>
		public delegate void ProgressEventHandler(int ProgressPercent, string TimeRemaining);
		private ProgressEventHandler ProgressEvent;
		
		public event ProgressEventHandler Progress
		{
			add
			{
				ProgressEvent = (ProgressEventHandler) System.Delegate.Combine(ProgressEvent, value);
			}
			remove
			{
				ProgressEvent = (ProgressEventHandler) System.Delegate.Remove(ProgressEvent, value);
			}
		}
		
		/// <summary>
		/// Occurs when status changes.
		/// </summary>
		public delegate void StatusEventHandler(string status);
		private StatusEventHandler StatusEvent;
		
		public event StatusEventHandler Status
		{
			add
			{
				StatusEvent = (StatusEventHandler) System.Delegate.Combine(StatusEvent, value);
			}
			remove
			{
				StatusEvent = (StatusEventHandler) System.Delegate.Remove(StatusEvent, value);
			}
		}
		
		/// <summary>
		/// Occurs when StdError of ffmpeg changes. Usefull for debugging or to display the command line to user.
		/// </summary>
		public delegate void ConsoleOutputEventHandler(string StdOut);
		private ConsoleOutputEventHandler ConsoleOutputEvent;
		
		public event ConsoleOutputEventHandler ConsoleOutput
		{
			add
			{
				ConsoleOutputEvent = (ConsoleOutputEventHandler) System.Delegate.Combine(ConsoleOutputEvent, value);
			}
			remove
			{
				ConsoleOutputEvent = (ConsoleOutputEventHandler) System.Delegate.Remove(ConsoleOutputEvent, value);
			}
		}
		
		/// <summary>
		/// Misc info such as fps, qfactor, time, bitrate.. Basicly, anything that is in the Stdout of ffmpeg and estimated size.
		/// </summary>
		public delegate void MiscInfoEventHandler(int Fps, int Qfactor, int Time, double Bitrate, int Frame, string Size, string EstimatedSize);
	    private MiscInfoEventHandler MiscInfoEvent;
		
        public event MiscInfoEventHandler MiscInfo
			{
				add
				{
					MiscInfoEvent = (MiscInfoEventHandler) System.Delegate.Combine(MiscInfoEvent, value);
				}
				remove
				{
					MiscInfoEvent = (MiscInfoEventHandler) System.Delegate.Remove(MiscInfoEvent, value);
				}
			}
		#endregion
		#region Libx264 Presets
		//TODO: Document all the presets.. for intellisense. Not very important right now
		//To use the x264 encoder, you will need to tell it which preset to use. if the user doesnt specify, the default will
		//be used. (see the example encoder for usage examples)
		//NOTE: Sorry, at this time i am unable to test the ipod presets. my ipod broke..But ill add them soon.
		public readonly string libx264_default = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method hex -subq 7 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 3 -directpred 1 -trellis 1 -flags2 +mixed_refs+wpred+dct8x8+fastpskip -wpredp 2";
		public readonly string libx264_fast = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method hex -subq 6 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 2 -directpred 1 -trellis 1 -flags2 +bpyramid+mixed_refs+wpred+dct8x8+fastpskip -wpredp 2 -rc_lookahead 30";
		public readonly string libx264_fast_firstpass = "-coder 1 -flags +loop -cmp +chroma -partitions -parti8x8-parti4x4-partp8x8-partb8x8 -me_method dia -subq 2 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 1 -directpred 1 -trellis 0 -flags2 +bpyramid-mixed_refs+wpred-dct8x8+fastpskip -wpredp 2 -rc_lookahead 30";
		public readonly string libx264_faster = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method hex -subq 4 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 2 -directpred 1 -trellis 1 -flags2 +bpyramid-mixed_refs+wpred+dct8x8+fastpskip -wpredp 1 -rc_lookahead 20";
		// Public ReadOnly libx264_faster_firstpass As String
		public readonly string libx264_fastfirstpass = "-coder 1 -flags +loop -cmp +chroma -partitions -parti8x8-parti4x4-partp8x8-partp4x4-partb8x8 -me_method dia -subq 2 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 1 -directpred 3 -trellis 0 -flags2 -bpyramid-wpred-mixed_refs-dct8x8+fastpskip -wpredp 2";
		public readonly string libx264_hq = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method umh -subq 8 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 2 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 4 -directpred 3 -trellis 1 -flags2 +wpred+mixed_refs+dct8x8+fastpskip -wpredp 2";
		public readonly string libx264_max = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partp4x4+partb8x8 -me_method tesa -subq 10 -me_range 24 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 2 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 16 -directpred 3 -trellis 2 -flags2 +wpred+mixed_refs+dct8x8-fastpskip -wpredp 2";
		public readonly string libx264_medium = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method hex -subq 7 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 3 -directpred 1 -trellis 1 -flags2 +bpyramid+mixed_refs+wpred+dct8x8+fastpskip -wpredp 2";
		public readonly string libx264_medium_firstpass = "-coder 1 -flags +loop -cmp +chroma -partitions -parti8x8-parti4x4-partp8x8-partb8x8 -me_method dia -subq 2 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 1 -directpred 1 -trellis 0 -flags2 +bpyramid-mixed_refs+wpred-dct8x8+fastpskip -wpredp 2";
		//  Public ReadOnly libx264_baseline As String
		public readonly string libx264_normal = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method hex -subq 6 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 2 -directpred 3 -trellis 0 -flags2 +wpred+dct8x8+fastpskip -wpredp 2";
		public readonly string libx264_slow = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method umh -subq 8 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 2 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 5 -directpred 3 -trellis 1 -flags2 +bpyramid+mixed_refs+wpred+dct8x8+fastpskip -wpredp 2 -rc_lookahead 50";
		//  Public ReadOnly libx264_slow_firstpass As String
		//  Public ReadOnly libx264_slower As String
		// Public ReadOnly libx264_slower_firstpass As String
		// Public ReadOnly libx264_slowfirstpass As String
		// Public ReadOnly libx264_superfast As String
		//Public ReadOnly libx264_superfast_firstpass As String
		public readonly string libx264_ultrafast = "-coder 0 -flags -loop -cmp +chroma -partitions -parti8x8-parti4x4-partp8x8-partb8x8 -me_method dia -subq 0 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 0 -i_qfactor 0.71 -b_strategy 0 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 0 -refs 1 -directpred 1 -trellis 0 -flags2 -bpyramid-mixed_refs-wpred-dct8x8+fastpskip-mbtree -wpredp 0 -aq_mode 0 -rc_lookahead 0";
		public readonly string libx264_ultrafast_firstpass = "-coder 0 -flags -loop -cmp +chroma -partitions -parti8x8-parti4x4-partp8x8-partb8x8 -me_method dia -subq 0 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 0 -i_qfactor 0.71 -b_strategy 0 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 0 -refs 1 -directpred 1 -trellis 0 -flags2 -bpyramid-mixed_refs-wpred-dct8x8+fastpskip-mbtree -wpredp 0 -aq_mode 0 -rc_lookahead 0";
		//  Public ReadOnly libx264_veryfast As String
		// Public ReadOnly libx264_veryfast_firstpass As String
		// Public ReadOnly libx264_veryslow As String
		// Public ReadOnly libx264_veryslow_firstpass As String
		public readonly string libx264_lossless_fast = "-coder 0 -flags +loop -cmp +chroma -partitions -parti8x8+parti4x4+partp8x8-partp4x4-partb8x8 -me_method hex -subq 3 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -directpred 1 -flags2 +fastpskip -cqp 0 -wpredp 0";
		public readonly string libx264_lossless_max = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partp4x4-partb8x8 -me_method esa -subq 8 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -refs 16 -directpred 1 -flags2 +mixed_refs+dct8x8+fastpskip -cqp 0 -wpredp 2";
		public readonly string libx264_lossless_medium = "-coder 1 -flags +loop -cmp +chroma -partitions -parti8x8+parti4x4+partp8x8+partp4x4-partb8x8 -me_method hex -subq 5 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -directpred 1 -flags2 +fastpskip -cqp 0 -wpredp 2";
		public readonly string libx264_lossless_slow = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partp4x4-partb8x8 -me_method umh -subq 6 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -refs 2 -directpred 1 -flags2 +dct8x8+fastpskip -cqp 0 -wpredp 2";
		public readonly string libx264_lossless_slower = "-coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partp4x4-partb8x8 -me_method umh -subq 8 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -refs 4 -directpred 1 -flags2 +mixed_refs+dct8x8+fastpskip -cqp 0 -wpredp 2";
		public readonly string libx264_lossless_ultrafast = "-coder 0 -flags +loop -cmp +chroma -partitions -parti8x8-parti4x4-partp8x8-partp4x4-partb8x8 -me_method dia -subq 0 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -directpred 1 -flags2 +fastpskip -cqp 0";
		private string _Libx264_custom; //of course you can create your own :) but if you dont select anything, Normal is what you get!
		private string _Libx264_custom_pass2;
		//TODO: finish off the presets. there is also the placebo presets and whatnot.
		#endregion
		#region Acodecs
		//TODO: Test and add more audio codecs
        public const string AudioCodec_Copy = "copy";
        public const string AudioCodec_NONE = "none";
        public const string AudioCodec_mp3 = "libmp3lame";
		//AAC got removed from ffmpeg due to not being free or something. the other aac is experimental.. so that blows..
		//but, its the only AAC encoder that is in the new build. here are the trade offs:
		//old build april 2009 -- has the libfaac aac encoder.. But alot of other things have changed or were messed up.
		//so we loose a GREAT aac encoder, BUT we gain the ability to update to newer autobuilds of ffmpeg.. Groovy.
        public const string AudioCodec_AAC = "aac -strict experimental"; //TODO: Note, if you upgrade ffmpeg, check to see
		//if the included aac encoder is still "experimental".
		#endregion
		#region Vcodecs
		//TODO: Test and add more video codecs
        public const string Vcodec_Copy = "copy";
        public const string Vcodec_h264 = "libx264";
        public const string Vcodec_flv = "flv";
        public const string Vcodec_Xvid = "libxvid";
        public const string Vcodec_NONE = "none";
		#endregion
		#region Containers
		//TODO: Test and add more containers
		
		//these containers are for when the user forces a container.. ie.. ffmpeg -i test.avi ~~~ -f flv Output.flv
		//NOTE: the encoder will "try" and determain the correct container based on the output file. SO, if the user
		//used output.flv as the outname, the encoder would "know" to use the FLV container format.
		//They arent manditory to use, but we will add them, because.. We are going to create guid named files without
		//an extension for the temp files. And thus, we will need to specify a container format..
        public const string Format_MKV = "matroska"; //for .mkv extension
        public const string Format_Matroska = "matroska"; //copy of above matroska.
        public const string Format_FLV = "flv";
        public const string Format_MOV = "mov";
        public const string Format_MP4 = "mp4";
        public const string Format_AVI = "avi";
        public const string Format_MP3 = "mp3"; //Note: Audio only
        public const string Format_AAC = "aac"; //NOTE: Audio only
		//THere is much to add. 3gp, ipod, ect.
		#endregion
		#region Audio Options
		private int _Aframes; //Set the number of audio frames to record. -aframes (int)
		private string _AFreq = "44100"; //sets the audio sampling frequency.. -ar 44100
		private string _AudioBitRate = "160k"; //-ab 128k
		private string _AudioChannels = "2"; //-ac 2 (default for 2 channel)
		#endregion
		#region video Options
		private string _VideoBitRate = "1000k";
		private string _Vframes; //number of frames to encode.. -vframes (int)
		private string _Vrate; //set frame rate.. -r 23.98
		private string _size; //sets frame size.. -s 720x480
		private string _aspect; //sets aspect ratio.. -aspect 4:3 (16:9, 1.3333, 1.7777 will work too)
		//TODO: Add more video option variables as needed
		// -metadata key=value -metadata title="my title"
		//TODO: Work on metadata keys.
		public readonly string RateControl_ABR = "abr";
		public readonly string RateControl_VBR = "vbr";
		public readonly string RateControl_CRF = "crf";
		#endregion
		#region Messages and exceptions
		//TODO: Create exceptions as needed. Make them as non-cryptic as possible as these will probably be
		//passed right to the end user.
		string InvalidRateControlOption = "CRF is not a valid rate control for the selected codec, the default bitrate will be used.";
		string SourceNotFound;
		
		#endregion
		#region variables //depreciated, see Audio/video options above :)
		private string _ffmpeg = ""; //Holds the Path of the ffmpeg executable.
		private string _Threads = "0"; //Default, Lets FFMpeg decide the number of threads
		private string _ACODEC = "copy"; //Default will be to copy the audio stream.
		private string _VideoCodec = "copy";
		private string _RateControl = "abr"; //choices are: "abr" for 1pass average bitrate
		//"vbr" for 2 pass variable bitrate or "crf" for constant rate factor
		private int _Crf = 17; //-crf 17 sounded like a good number :) If your using -crf then you know what you want this set as.
		private bool _Overwrite = false;
		private string _Container;
		private string _TempName;
		private bool _Analyzed = false;
		private int _TotalFrames;
		private bool _AnalyzedFailed = false;
		
		
		private ProcessStartInfo _FFmpegProcessPropertys = new ProcessStartInfo(); //TODO: give unique process id & name
		
		private int _seconds;
		private string _thumb; //Will hold the path name of the thumbnail.
		private bool _ThumbGenerated = false;
		private ArrayList _ThumbnailList = new ArrayList(); //Will hold a list of all temperary thumbnails generated, so they can be deleted
		//when the garbage collector cleans up.
		
		
		//Note: Commmand line will go as follows,
		//-i <infile> <Custom params ie. -map> <audio options> <video options> <libx264 pre (if needed)> <Thread count> <container> <output>
		private string _Source;
		private string _AudioParams;
		private string _VideoParamsPass1;
		private string _VideoParamsPass2;
		private string _CustomParams; //-map 0:0 -map 0:1 for example
		private string _OutputDirectory; //ie. d:\encoded files\
		private string _FileName; //ie.. Encoded.mkv: if one isnt selected one will be created from input name
		private string _CommandPass1;
		private string _CommandPass2;
		#endregion
		#region File Types
		ArrayList _AudioFileTypes = new ArrayList();
		private void AddAudioFiles()
		{
			//TODO: ad any known "audio only" File types.. ie.. mp3, aac..
			//we will check this list, if the input file is audio only
			//then we can auto disable the video encoding.
			_AudioFileTypes.Add(".mp3");
			_AudioFileTypes.Add(".wmv");
			_AudioFileTypes.Add(".flac");
			_AudioFileTypes.Add(".aac");
			_AudioFileTypes.Add(".ac3");
			_AudioFileTypes.Add(".aif");
			_AudioFileTypes.Add(".at3");
			_AudioFileTypes.Add(".ogg");
			_AudioFileTypes.Add(".wav");
			//_AudioFileTypes.Add(".cda") NOT SUPPORTED in ffmpeg. sorry, you'll have to rip your cd's some other way.
			//NOTE: ive not tested all of these extensions. also, if an input file is added with an extension
			//from the above list it will over-ride the video settings to -vn (no video encoding).
			//This is to prevent any errors with ffmpeg. as of right now, there is no code to combine audio or video
			//or different sources. So if you want to put fourth the effort that is great.
		}
		#endregion
		#region Private Methods
		private void SetupAudio()
		{
			if (_ACODEC == "copy")
			{
				_AudioParams = "-acodec copy";
			}
			else if (_ACODEC == "none")
			{
				_AudioParams = "-an";
			}
			else
			{
				_AudioParams = string.Format("{0} {1} {2} {3} {4}", FAudiocodec(), FAudioBitrate(), FAudioFrequency(), FAudioChannels(), FAudioFrames());
			}
		}
		private void SetupVideo()
		{
			ValidRateControl(); //will test against codec, and make sure the rate control selected will work.
			switch (_RateControl)
			{
				case "abr":
					if (_VideoCodec == "copy")
					{
						_VideoParamsPass1 = "-vcodec copy";
					}
					else if (_VideoCodec == "none")
					{
						_VideoParamsPass1 = "-vn";
					}
					else if (_VideoCodec == Vcodec_h264)
					{
						_VideoParamsPass1 = string.Format("{0}{1}{2}{3}{4}{5} {6}", FVideoCodec(), FVideoBitrate(), FVideoFrames(), FVideoFrameRate(), FVideoSize(), FVideoAspect(), _Libx264_custom);
					}
					else
					{
						_VideoParamsPass1 = string.Format("{0}{1}{2}{3}{4}{5}", FVideoCodec(), FVideoBitrate(), FVideoFrames(), FVideoFrameRate(), FVideoSize(), FVideoAspect());
					}
					break;
				case "vbr":
					if (_VideoCodec == "copy")
					{
						_VideoParamsPass1 = "-vcodec copy";
						_VideoParamsPass2 = "-vcodec copy";
					}
					else
					{
						if (_VideoCodec == Vcodec_h264)
						{
							_VideoParamsPass1 = string.Format("{0}{1}{2}{3}{4}{5}{6} {7}", "-pass 1 ", FVideoCodec(), FVideoBitrate(), FVideoFrames(), FVideoFrameRate(), FVideoSize(), FVideoAspect(), _Libx264_custom);
							_VideoParamsPass2 = string.Format("{0}{1}{2}{3}{4}{5}{6} {7}", "-pass 2 ", FVideoCodec(), FVideoBitrate(), FVideoFrames(), FVideoFrameRate(), FVideoSize(), FVideoAspect(), _Libx264_custom_pass2);
							
						}
						else
						{
							_VideoParamsPass1 = string.Format("{0}{1}{2}{3}{4}{5}{6}", "-pass 1 ", FVideoCodec(), FVideoBitrate(), FVideoFrames(), FVideoFrameRate(), FVideoSize(), FVideoAspect());
							_VideoParamsPass2 = string.Format("{0}{1}{2}{3}{4}{5}{6}", "-pass 2 ", FVideoCodec(), FVideoBitrate(), FVideoFrames(), FVideoFrameRate(), FVideoSize(), FVideoAspect());
						}
					}
					break;
				case "crf": //User should have chosen libx264!
					_VideoParamsPass1 = string.Format("{0}{1}{2}{3}{4}{5} {6}", FVideoCodec(), FVideoBitrate(), FVideoFrames(), FVideoFrameRate(), FVideoSize(), FVideoAspect(), _Libx264_custom);
					break;
			}
		}
		private void SetupCommandPass1()
		{
			//command line should go something like: -i <source> <custom params> -pass 1 -an _videoparamspas1 -threads int NUL
			if (_RateControl == RateControl_VBR)
			{
				//1st of 2 pass, NO audio, output to nul
				_CommandPass1 = string.Format("-i {0} {1} {2} {3} {4} {5}{6}", _Source, _CustomParams, "-an", _VideoParamsPass1, "-threads " + _Threads, "-y", "nul");
				
			}
			else
			{
				//single pass only.
				_CommandPass1 = string.Format("-i {0} {1} {2} {3} {4} {5}{6}", _Source, _CustomParams, _AudioParams, _VideoParamsPass1, "-threads " + _Threads, "\"" + _OutputDirectory, _FileName + "\"");
			}
		}
		private void SetupCommandPass2()
		{
			//second pass, WITH audio
			//command line should go something like: -i <source> <custom params> -pass 1 _audioparams2 _videoparamspas2 -threads int <out>
			_CommandPass2 = "";
		}
		private bool ValidRateControl()
		{
			//As far as i know (could be more but ive not yet tested) h264 is the only encoder
			//that uses -crf (int) flag. However, if another codec supports it, just add it below
			if (_RateControl == "crf")
			{
				switch (_VideoCodec)
				{
					//TODO: Test other encoders for crf useability and add them below
				case "libx264":
					return true;
				default:
					_RateControl = RateControl_ABR;
					return false;
			}
			
		}
		else
		{
			return true;
		}
	}
	//Private Sub RenameFile()
	//    Try
	//        My.Computer.FileSystem.RenameFile(_OutputDirectory & _TempName, _FileName)
	//    Catch ex As Exception
	
	//    End Try
	//End Sub
	private void RunEncode(string Argument)
	{
		if (TargetExists() == true)
		{
			if (_Overwrite == true)
			{
				//delete file..
				try
				{
                    System.IO.File.Delete(_OutputDirectory + _FileName);
				}
				catch (Exception)
				{
				}
			}
			else
			{
				Exception TargetAlreadyExistsException = new Exception("The Target file already exists");
				throw (TargetAlreadyExistsException);
			}
		}


        _FFmpegProcessPropertys.Arguments = Argument;// "-i \"C:\\Users\\Public\\Videos\\Sample Videos\\Wildlife.wmv\"  -acodec libmp3lame -ab 128k -ar 44100 -ac 2  -vcodec libx264 -b 1000k -coder 1 -flags +loop -cmp +chroma -partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method hex -subq 6 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -refs 2 -directpred 1 -trellis 1 -flags2 +bpyramid+mixed_refs+wpred+dct8x8+fastpskip -wpredp 2 -rc_lookahead 30 -threads 0 \"C:\\Users\\Administrator\\Desktop\\Wildlife.flv\"";
		_FFmpegProcessPropertys.UseShellExecute = false;
		_FFmpegProcessPropertys.RedirectStandardOutput = true;
		_FFmpegProcessPropertys.RedirectStandardError = true;
		_FFmpegProcessPropertys.CreateNoWindow = true;
		var FFmpegProcess = Process.Start(_FFmpegProcessPropertys);
		System.IO.StreamReader readerStdOut = FFmpegProcess.StandardError;
		string sOutput;
		while (readerStdOut.EndOfStream == false)
		{
			sOutput = readerStdOut.ReadLine();
			if (ConsoleOutputEvent != null)
				ConsoleOutputEvent(sOutput);
			// RaiseEvent Percent(GetPercent(sOutput, TotalFrames))
			int Percent = GetPercent(sOutput);
			if (ProgressEvent != null)
				ProgressEvent(Percent, Timeleft(sOutput));
			
		}
		FFmpegProcess.WaitForExit();
		FFmpegProcess.Close();
		
		
	}
	#endregion
	#region Private Functions
	private string FVideoCodec()
	{
		switch (_VideoCodec)
		{
			case "copy":
				return "-vcodec copy";
			case "none":
				return "-vn"; //should never return. But just in case..
			default:
				return "-vcodec " + _VideoCodec;
		}
	}
	private string FVideoBitrate()
	{
		if (_RateControl == "crf")
		{
			return " -crf " + _Crf;
		}
		else
		{
			return " -b " + _VideoBitRate;
		}
	}
	private string FVideoFrames()
	{
		if (_Vframes == null)
		{
			return "";
		}
		else
		{
			return " -vframes " + _Vframes;
		}
	}
	private string FVideoFrameRate()
	{
		if (_Vrate == null)
		{
			return "";
		}
		else
		{
			return " -r " + _Vrate;
		}
	}
	private string FVideoSize()
	{
		if (_size == null)
		{
			return "";
		}
		else
		{
			return " -s " + _size;
		}
	}
	private string FVideoAspect()
	{
		if (_aspect == null)
		{
			return "";
		}
		else
		{
			return " -aspect " + _aspect;
		}
	}
	private string FAudioFrames()
	{
		if (_Aframes == null || _Aframes == 0)
		{
			return "";
		}
		else
		{
			return "-aframes " + _Aframes;
		}
	}
	private string FAudioChannels()
	{
		return "-ac " + _AudioChannels;
	}
	private string FAudioFrequency()
	{
		return "-ar " + _AFreq;
	}
	private string FAudioBitrate()
	{
		return "-ab " + _AudioBitRate;
	}
	private string FAudiocodec()
	{
		return "-acodec " + _ACODEC;
	}
	//TODO: Add code to the Analyze functions to get stream information!
	private bool QuickAnalyze()
	{
		ProcessStartInfo infoprocess = new ProcessStartInfo();
		infoprocess.Arguments = (string) ("-i " + _Source); //-an -vcodec copy -f rawvideo -y null"
		infoprocess.UseShellExecute = false;
		infoprocess.RedirectStandardError = true;
		infoprocess.CreateNoWindow = true;
		infoprocess.FileName = _ffmpeg;
		var FFmpegProcess = Process.Start(infoprocess);
		System.IO.StreamReader readerStdOut = FFmpegProcess.StandardError;
		string sOutput;
		int hours;
		int minutes;
		int seconds = 0;
		//So far, from what i can tell, ffmpeg will get a pretty good time IN SECONDS
		//On vob files, mostly ones with broken headers will report the wrong time
		//with the message max_analyze_duration reached. so, for now, we will assume
		//that if we dont get the MAD reached message we got good info.
		while (readerStdOut.EndOfStream == false)
		{
			sOutput = readerStdOut.ReadLine();
			//check for MAD reached message
			if (sOutput.Contains("max_analyze_duration") == true)
			{
				FFmpegProcess.Close();
				return false; //ie, we werent able to perform a quick info analisys.
			}
			else
			{
				if (sOutput.Contains("Duration:")) //We want time to determain progress.
				{
					string[] split1 = sOutput.Split(new char[] {' ', ','});
					string String1 = split1[3];
					string[] times = String1.Split(new char[] {':'});
					try
					{
						hours = int.Parse(times[0]);
						minutes = int.Parse(times[1]);
						seconds = int.Parse(times[2]);
						hours = hours * 60;
						minutes = minutes + hours;
						minutes = minutes * 60;
						_seconds = seconds + minutes;
					}
					catch (Exception)
					{
						FFmpegProcess.Close();
						return false;
					}
				}
				string Fps;
				if (sOutput.Contains(" fps,")) //We want fps, so we can determain total frames so we can get ETA of completion.
				{
					try
					{
						string[] split1 = sOutput.Split(new char[] {' ', ','});
						string s1 = split1[20];
						Fps = s1;
					}
					catch (Exception)
					{
						FFmpegProcess.Close();
						return false;
					}
				}
				else
				{
					FFmpegProcess.Close();
					return false;
				}
				//Encase in a try/catch, just in case FPS pulled from the console is something besides a number.. :)
				try
				{
					_TotalFrames = seconds * Convert.ToInt32(Fps);
				}
				catch (Exception)
				{
					FFmpegProcess.Close();
					return false;
				}
			}
		}
		FFmpegProcess.WaitForExit();
		FFmpegProcess.Close();
		return true;
	}
	private bool SlowAnalyze()
	{
		ProcessStartInfo infoprocess = new ProcessStartInfo();
		infoprocess.Arguments = "-i " + _Source + " -an -vcodec copy -f rawvideo -y nul";
		infoprocess.UseShellExecute = false;
		infoprocess.RedirectStandardError = true;
		infoprocess.CreateNoWindow = true;
		infoprocess.FileName = _ffmpeg;
		var FFmpegProcess = Process.Start(infoprocess);
		System.IO.StreamReader readerStdOut = FFmpegProcess.StandardError;
		string sOutput;
		var frame = "";
		var fps = "";
		var qfac = "";
		var size = "";
		var time = "";
		var br = "";
		while (readerStdOut.EndOfStream == false)
		{
			sOutput = readerStdOut.ReadLine();
			if (ConsoleOutputEvent != null)
				ConsoleOutputEvent(sOutput);
			if (sOutput.Contains("frame="))
            {
                #region
                try
				{
					string[] OutLine = sOutput.Split(new char[] {'='});
					string[] chunk1 = OutLine[1].Split(new char[] {' '}); //Frame
					string[] chunk2 = OutLine[2].Split(new char[] {' '}); //fps (speed of encoding, NOT the actual frame rate)
					string[] chunk3 = OutLine[3].Split(new char[] {' '}); //qfactor
					string[] chunk4 = OutLine[4].Split(new char[] {' '}); //size
					string[] chunk5 = OutLine[5].Split(new char[] {' '}); //time
					string[] chunk6 = OutLine[6].Split(new char[] {' '}); //bitrate
					//the above chunks had to be split.
					//the ones we care about are FRAME AND TIME: Now, because on short files
					//there may be many spaces, ie frames=     32 is different than frames=  3343 <--note less spaces.
					bool TimeHit = false;
					bool FrameHit = false;
					bool fpshit = false;
					bool qfachit = false;
					bool sizehit = false;
					bool brhit = false;
					for (var index = 0; index <= chunk1.Count() - 1; index++) //should account for enuff spaces!
					{
						if (chunk1[index] != "" && FrameHit == false)
						{
							frame = chunk1[index];
							FrameHit = true;
						}
					}
					for (var index = 0; index <= chunk5.Count() - 1; index++) //should account for enuff spaces!
					{
						if (chunk5[index] != "" && TimeHit == false)
						{
							time = chunk5[index];
							TimeHit = true;
						}
					}
					//If chunk5(index) <> "" And TimeHit = False Then
					//    time = chunk5(index)
					//    TimeHit = True
					//End If
					//frame = chunk1(0)
					//fps = chunk2(0)
					//qfac = chunk3(0)
					//size = chunk4(0)
					//time = chunk5(0)
					//br = chunk6(0)
				}
				catch (Exception)
				{
					//do nothing, prolly an audio file. Besides, all a failure here means is no progress, lol.
					//basicly, the progress will have to be intermanate.
					FFmpegProcess.Kill();
					FFmpegProcess.Close();
					return false;
                }
                #endregion
            }
		}

        try
        {
            _seconds = Convert.ToInt32(time);
        }
        catch { }

        try
        {
            _TotalFrames = Convert.ToInt32(frame);
        }
        catch { }
	
		
		FFmpegProcess.WaitForExit();
		FFmpegProcess.Close();
		return true;
	}
	private bool SourceExists()
	{
		if (System.IO.File.Exists(_Source.Replace("\"", "")) == true)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	private bool IsVideo()
	{
		//first, parse the file extension from the input file, check if its on the audio list..
        string FileExt = System.IO.Path.GetExtension(_Source.Replace("\"","").Trim()).ToLower();
		if (_AudioFileTypes.Contains(FileExt) == true)
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	private string GenerateThumb()
	{
		if (_ThumbGenerated == true)
		{
			return _thumb;
		}
		else
		{
			_thumb = "";
			if (SourceExists() == true)
			{
				AnalyzeFile();
				int Seconds = 1;
				if (_seconds > 45)
				{
					Seconds = 45;
				}
				else
				{
					Seconds = _seconds;
				}
				try
				{
					_thumb = System.IO.Path.GetTempPath() + System.Guid.NewGuid().ToString() + ".jpg"; //Create a new filename...
				}
				catch (Exception)
				{
					return _thumb; //file creation failed for some reason. return nothin, get outta here.
				}
				_ThumbnailList.Add(_thumb);
				string Params = string.Format("-i {0} \"{1}\" -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", _Source, _thumb, Seconds);
				_FFmpegProcessPropertys.Arguments = @Params;
				_FFmpegProcessPropertys.UseShellExecute = false;
				_FFmpegProcessPropertys.RedirectStandardOutput = true;
				_FFmpegProcessPropertys.RedirectStandardError = true;
				_FFmpegProcessPropertys.CreateNoWindow = true;
				var FFmpegProcess = Process.Start(_FFmpegProcessPropertys);
				System.IO.StreamReader readerStdOut = FFmpegProcess.StandardError;
				string sOutput;
				while (readerStdOut.EndOfStream == false)
				{
					sOutput = readerStdOut.ReadLine();
					if (ConsoleOutputEvent != null)
						ConsoleOutputEvent(sOutput);
					if (StatusEvent != null)
						StatusEvent(string.Format("Generating thumbnail for {0}", _FileName));
				}
				FFmpegProcess.WaitForExit();
				FFmpegProcess.Close();
				_ThumbGenerated = true;
				return _thumb;
			}
			else
			{
				_ThumbGenerated = true;
				return _thumb;
			}
		}
	}
	private string GetFileName()
	{
		//NOTE: Even tho ffmpeg does this for you, we will do it ourselfs, we may remove it later. who knows.
		//This will run and check if user entered in a custom filename. ie, encoded.mkv
		//if not, then we will create on based on the container(if set) OR the codec
		string SourceExt = System.IO.Path.GetExtension(_Source.Trim("\"".ToCharArray()));
        string SourceName = System.IO.Path.GetFileNameWithoutExtension(_Source.Trim("\"".ToCharArray()));
		//We now have JUST the name of the source file, with No extension, now we need to add an extension based on
		//the codec, or preferably the container if it was set..
		if (string.IsNullOrEmpty(_FileName)) //User didnt specify a custom filename, lets create one.
		{
			//BTW, we are gonna do somethin i HATE doing, which is alotta nested directions. so lets get focused.
			if (string.IsNullOrEmpty(_Container))
			{
				//generate file based on codec!
				//Note, we must check for audio only!
				if (IsVideo() == true)
				{
					//check the video containers.
					switch (_VideoCodec)
					{
						case Vcodec_Copy:
							//We shoulda checked this before. But the in and outfile can stay the same
							//I hope the user CHANGED the output directory to something different! haha
							return SourceName + SourceExt;
						case Vcodec_flv:
							return SourceName + ".flv";
						case Vcodec_h264:
							return SourceName + ".mp4";
						case Vcodec_Xvid:
							return SourceName + ".mp4";
							//TODO: if you add more codecs, and they would use another ext, like REAL media for example
							//add them. otherwise, just do a CASE ELSE, and add a default like avi or mp4.
					}
				}
				else
				{
					//check the audio containers.
					switch (_ACODEC)
					{
						case AudioCodec_AAC:
							return SourceName + ".aac";
						case AudioCodec_Copy:
							return SourceName + SourceExt;
						case AudioCodec_mp3:
							return SourceName + ".mp3";
							//TODO: Do the same for audio formats as you did for video.
					}
				}
			}
			else
			{
				//generate file based on container(which is preferable)
				switch (_Container)
				{
					case Format_AAC:
						return SourceName + ".aac";
					case Format_AVI:
						return SourceName + ".avi";
					case Format_FLV:
						return SourceName + ".flv";
					case Format_Matroska:
						return SourceName + ".mkv";
					case Format_MOV:
						return SourceName + ".mov";
					case Format_MP3:
						return SourceName + ".mp3";
					case Format_MP4:
						return SourceName + ".mp4";
					default:
						break;
				}
			}
			return SourceName;
		}
		else //then return what the user entered in for the filename.
		{
			return _FileName;
		}
	}
	private bool TargetExists()
	{
		if (System.IO.File.Exists(_OutputDirectory + _FileName) == true)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	private string TempName()
	{
		_TempName = System.Guid.NewGuid().ToString();
		return _TempName;
	}
	private int GetPercent(string Cout)
	{
		int Frame = 0;
		if (Cout.Contains("frame="))
		{
			try
			{
				string[] OutLine = Cout.Split(new char[] {'='});
				string[] chunk1 = OutLine[1].Split(new char[] {' '}); //Frame
				string[] chunk2 = OutLine[2].Split(new char[] {' '}); //fps (speed of encoding, NOT the actual frame rate)
				string[] chunk3 = OutLine[3].Split(new char[] {' '}); //qfactor
				string[] chunk4 = OutLine[4].Split(new char[] {' '}); //size
				string[] chunk5 = OutLine[5].Split(new char[] {' '}); //time
				string[] chunk6 = OutLine[6].Split(new char[] {' '}); //bitrate
				//the above chunks had to be split.
				//the ones we care about are FRAME AND TIME: Now, because on short files
				//there may be many spaces, ie frames=     32 is different than frames=  3343 <--note less spaces.
				bool TimeHit = false;
				bool FrameHit = false;
				bool fpshit = false;
				bool qfachit = false;
				bool sizehit = false;
				bool brhit = false;
				
				for (var index = 0; index <= chunk1.Count() - 1; index++) //should account for enuff spaces!
				{
					if (chunk1[index] != "" && FrameHit == false)
					{
						Frame = int.Parse(chunk1[index]);
						FrameHit = true;
					}
				}
				
				//If chunk5(index) <> "" And TimeHit = False Then
				//    time = chunk5(index)
				//    TimeHit = True
				//End If
				//frame = chunk1(0)
				//fps = chunk2(0)
				//qfac = chunk3(0)
				//size = chunk4(0)
				//time = chunk5(0)
				//br = chunk6(0)
                return (Frame * 100)/ _TotalFrames;
			}
			catch (Exception)
			{
			}
		}
		return 0;
	}
	private string Timeleft(object Cout)
	{
		return null;
	}
	#endregion
	#region constructors
	/// <summary>
	/// Initializes a new instance of the <see cref="Encoder" /> class.
	/// </summary>
	public VideoEncoder()
	{
        _ffmpeg = AppDomain.CurrentDomain.BaseDirectory + @"ffmpeg\ffmpeg.exe";
		_FFmpegProcessPropertys.FileName = _ffmpeg;
	}
	/// <summary>
	/// Initializes a new instance of the <see cref="Encoder" /> class.
	/// </summary>
	/// <param name="FFmpeg">The FFmpeg executable location.</param>
    public VideoEncoder(string FFmpeg)
	{
		_ffmpeg = FFmpeg;
		_FFmpegProcessPropertys.FileName = _ffmpeg;
	}
	#endregion
	#region Public Methods
	public void AnalyzeFile()
	{
		//this may be called explicitly, or it should run automaticly before the encoder is ran
		//It can be be called so if the user wanted to analyze files as added ect ect..
		//Also, we need to check to see if its a video file, because we wont analyze audio files. no point.
		if (IsVideo() == true)
		{
			if (_Analyzed == false)
			{
				if (StatusEvent != null)
					StatusEvent("分析文件...");
				if (QuickAnalyze() == false) //Meaning Couldn't get the info by doing a quick analyze
				{
					if (SlowAnalyze() == false)
					{
						_AnalyzedFailed = true;
					}
				}
				_Analyzed = true;
			}
		}
		
	}
	public void Encode()
	{
		//Time to get to work, and encode a file.
		if (SourceExists() == true) //else do nothing, will error out anyways. ANd again, we will check when we analyze
		{
			if (StatusEvent != null)
				StatusEvent("配置解码器...");
			AnalyzeFile();
			_FileName = GetFileName();
			SetupAudio();
			SetupVideo();
			if (_RateControl == RateControl_VBR)
			{
				SetupCommandPass1();
				SetupCommandPass2();
				if (StatusEvent != null)
					StatusEvent("Running Pass 1");
				RunEncode(_CommandPass1);
				if (StatusEvent != null)
					StatusEvent("Running Pass 2");
				RunEncode(_CommandPass2);
			}
			else
			{
				if (StatusEvent != null)
					StatusEvent("解码中...");
				SetupCommandPass1();
				RunEncode(_CommandPass1);
			}
			//RenameFile()
		}
		if (StatusEvent != null)
			StatusEvent("视频转换结束!");
	}
	#endregion
	#region Propertys
	public string SourceFile
	{
		get
		{
			return _Source;
		}
		set
		{
			_Source = "\"" + value + "\"";
            //_Source = value;
			_ThumbGenerated = false;
			_Analyzed = false;
			_AnalyzedFailed = false;
			_FileName = "";
		}
	}
	public string Format
	{
		get
		{
			return _Container;
		}
		set
		{
			_Container = value;
		}
	}
	public string AudioCodec
	{
		get
		{
			return _ACODEC;
		}
		set
		{
			_ACODEC = value;
		}
	}
	public string Video_Codec
	{
		get
		{
			return _VideoCodec;
		}
		set
		{
			_VideoCodec = value;
		}
	}
	public string AudioBitrate
	{
		get
		{
			return _AudioBitRate;
		}
		set
		{
			_AudioBitRate = value;
		}
	}
	public string VideoBitrate
	{
		get
		{
			return _VideoBitRate;
		}
		set
		{
			_VideoBitRate = value;
		}
	}
	public string Threads
	{
		get
		{
			return _Threads;
		}
		set
		{
			_Threads = value;
		}
	}
	public bool OverWrite
	{
		get
		{
			return _Overwrite;
		}
		set
		{
			_Overwrite = value;
		}
	}
	public int ConstantRateFactor
	{
		get
		{
			return _Crf;
		}
		set
		{
			_Crf = value;
		}
	}
	public string RateControl
	{
		get
		{
			return _RateControl;
		}
		set
		{
			_RateControl = value;
		}
	}
	public string Libx264_Preset_pass1
	{
		get
		{
			return _Libx264_custom;
		}
		set
		{
			_Libx264_custom = value;
		}
	}
	public string Libx264_Preset_pass2
	{
		get
		{
			return _Libx264_custom_pass2;
		}
		set
		{
			_Libx264_custom_pass2 = value;
		}
	}
	public string OutputPath
	{
		get
		{
			return _OutputDirectory;
		}
		set
		{
			if (value.EndsWith("\\"))
			{
				if (System.IO.Directory.Exists(value) == false)
				{
					System.IO.Directory.CreateDirectory(value);
				}
				_OutputDirectory = value;
			}
			else
			{
				if (System.IO.Directory.Exists(value + "\\") == false)
				{
					System.IO.Directory.CreateDirectory(value + "\\");
				}
				_OutputDirectory = value + "\\";
			}
			
		}
	}
	public string ThumbNail
	{
		get
		{
			return GenerateThumb();
		}
	}
	public string Filename
	{
		get
		{
			return _FileName;
		}
		set
		{
			_FileName = value;
		}
	}
	public string CustomParams
	{
		get
		{
			return _CustomParams;
		}
		set
		{
			_CustomParams = value;
		}
	}
	#endregion
	//We need to create code to: Encode file, set up command lines
	//    Private Function GetPercent(ByVal Output As String, ByVal TotalFrames As Integer) As Integer
	//        If Output.Contains("frame=") Then
	//            Dim split2 As String() = Output.Split(New [Char]() {"="})
	//            Dim frameslpit = split2(1)
	//            Dim frame1 = frameslpit.Replace(" ", "")
	//            Dim frame2 = frame1.Replace("fps", "")
	//            If frame2 < TotalFrames Then
	//                Dim Percent = (frame2 / TotalFrames) * 100
	//                Return Percent
	//            Else
	//                Return 0
	//            End If
	//        End If
	//        Return 0
	//    End Function
	
	
	//    Private Function Arguments() As String
	//        Dim params As String
	//        'determan what ratecontrol option the user wanted.
	//        Dim RC As String
	//        Select Case _RateControl
	//            Case 0
	//                RC = "-crf " & _Crf.ToString & " "
	//            Case 1
	//                RC = "-pass 1 -b " & _VideoBitRate & " " 'TODO: add code for second pass!!!!
	//            Case 2
	//                RC = "-pass 2 -b " & _VideoBitRate & " "
	//            Case Else
	//                'mmm, then coder made error, throw exception.
	//                Dim IncorrectRateControlTypeException As New Exception("Incorrect Rate controll selection. 0=crf, 1=single pass, 2= 2 pass")
	//                Throw IncorrectRateControlTypeException
	//        End Select
	//        params = "-i " & """" & _Source & """" & " -vcodec " & _VideoCodec & " " & RC & " -threads " & _Threads & " " & _CustomParams & " -acodec " & _ACODEC & " -ab " & _AudioBitRate & " -f " & Container & " " & """" & _OutputFile & "\" & TempName() & """"
	
	//        'params = "-i " & """" & _Source & """" & " -vcodec " & _VideoCodec & " " & RC & " -threads " & _Threads & " " & _CustomParams & " -acodec " & _ACODEC & " -ab " & _AudioBitRate & " " & """" & _OutputFile & """"
	//        My.Computer.Clipboard.Clear()
	//        My.Computer.Clipboard.SetText(params)
	//        MsgBox(params)
	//        Return params
	//    End Function
	
	
	//#End Region
	//#Region "Methods"
	
	
	
	
	//#End Region
	
	#region IDisposable Support
	private bool disposedValue; // To detect redundant calls
	
	// IDisposable
	protected virtual void Dispose(bool disposing)
	{
		if (! this.disposedValue)
		{
			if (disposing)
			{
				// TODO: dispose managed state (managed objects).
			}
			
			// TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
			// TODO: set large fields to null.
			
			//When the garbage collector tears down the encoder, It will delete any thumbnail files
			//created in the temp directory.
			foreach (var Thumbs in _ThumbnailList)
			{
				if (System.IO.File.Exists(Thumbs.ToString()) == true)
				{
					try
					{
						if (StatusEvent != null)
							StatusEvent(string.Format("Removing generated thumbnail from system: {0}", Thumbs));
						System.IO.File.Delete(Thumbs.ToString());
					}
					catch (Exception)
					{
						//If for some reason it cannot access the file, then do nothing.
					}
				}
			}
		}
		this.disposedValue = true;
	}
	
	// TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
	~VideoEncoder()
	{
		// Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
		Dispose(false);
		//		base.Finalize();
	}
	
	// This code added by Visual Basic to correctly implement the disposable pattern.
	public void Dispose()
	{
		// Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
		Dispose(true);
		GC.SuppressFinalize(this);
	}
	#endregion
	

    }
}
